//实现异步工作器
//异步工作器使用双缓冲区思想
//外界将任务数据,添加到缓冲区中
//异步线程对缓冲区中的数据进行处理,弱缓冲区中没有数据了则交换缓冲区

//实现:
//管理的成员
//1.双缓冲区
//2.互斥锁,保证线程安全
//3.条件变量-生产消费,模型
//4.回调函数(针对缓冲区中的数据处理接口--外界传入一个函数,告诉异步工作器数据该如何处理)

//提供的操作
//1.停止异步工作器
//2.添加到数据缓冲区
//私有操作:创建线程,线程入口函数,交换缓冲区,对消费缓冲区数据使用回调函数进行处理,处理完之后再次交换


#ifndef __M_LOOPER_H__
#define __M_LOOPER_H__

#include<thread>
#include<mutex>
#include<functional>
#include<atomic>
#include<condition_variable>
#include"buffer.hpp"

namespace zllog
{
    using Functor = std::function<void(Buffer&)>;

    enum class AsyncType
    {
        ASYNC_SAFE = 1,
        ASYNC_UNSAFE = 2
    };

    class AsyncLooper
    {
    public:
        using ptr = std::shared_ptr<AsyncLooper>;
        AsyncLooper(const Functor& cb,AsyncType looper_type = AsyncType::ASYNC_SAFE)
            :_stop(false)
            ,_thread(std::thread(&AsyncLooper::threadEntry,this))         //
            ,_callBack(cb)
            ,_looper_type(looper_type)
        {}
        ~AsyncLooper()
        {
            stop();
        }
        void stop()
        {
            //将退出标志设置为true
            _stop = true;
            //唤醒所有的工作线程
            _cond_con.notify_all();
            _thread.join();
        }
        void push(const char* data,size_t len)
        {
            //1.无线扩容--非安全         2.固定大小--生产缓冲区中数据满了就阻塞
            std::unique_lock<std::mutex> lock(_mutex);
            {
                //条件变量控制,若剩余空间大小大于数据长度,则可以添加数据
                if(_looper_type == AsyncType::ASYNC_SAFE)
                {
                    _cond_pro.wait(lock,[&]()->bool{
                        if(_pro_buf.writeAbleSize() >= len)
                        {
                            return true;
                        }
                    });
                }
                //能够走下来,代表满足了条件,可以向缓冲区中添加数据
                _pro_buf.push(data,len);
                //唤醒消费者对缓冲区中的数据进行处理
                _cond_con.notify_one();
            }
        }
    private:
        void threadEntry()   //线程入口函数--对消费者缓冲区中的数据进行处理,处理完毕后,初始化缓冲区,交换缓冲区
        {
            while(1)
            {
                {
                    //1.判断生产缓冲区有没有数据,有则交换,无则阻塞
                    std::unique_lock<std::mutex> lock(_mutex);
                    //退出标志被设置,且缓冲区已经没有数据了,这时候再退出,否则有可能生产缓冲区有数据,但没有被完全处理
                    if(_stop && _pro_buf.empty())
                    {
                        break;
                    }
                    //若当前是退出前被唤醒,或者有数据被唤醒,则返回真,继续向下运行,否则陷入休眠
                    _cond_con.wait(lock,[&]()->bool{
                        if(!_pro_buf.empty() || _stop)      
                        {
                            return true;
                        }
                    });
                    _con_buf.swap(_pro_buf);
                    //2.唤醒所有生产者
                    if(_looper_type == AsyncType::ASYNC_SAFE)
                        _cond_pro.notify_all();
                }
                //3.被唤醒后,对消费者缓冲区进行数据处理
                _callBack(_con_buf);
                //4.初始化消费缓冲区
                _con_buf.reset();
            }
        }
    private:
        Functor _callBack;         //具体对缓冲区数据进行处理的回调函数,由异步工作器使用者传入
    private:
        AsyncType _looper_type; 
        std::atomic<bool> _stop;   //工作器停止标志
        Buffer _pro_buf;           //生产缓冲区
        Buffer _con_buf;           //消费缓冲区
        std::mutex _mutex;  
        std::condition_variable _cond_pro;
        std::condition_variable _cond_con;
        std::thread _thread;    

    };






};



#endif